<?

function ____createO($class, $args)
{
    $num = count($args);
    $cmd = array();
    for ($i=0; $i < $num; $i++) {
        $cmd[] = "\$args[{$i}]";
    }
    $result = null;
    eval("\$result = new {$class}(" . implode(',', $cmd) . ");");
    return $result;
}

class CData
{
    protected $data;
    protected $charset;
    const DEFAULT_CHARSET = 'Windows-1251';

    function __construct($data='', $charset=self::DEFAULT_CHARSET)
    {
        $this->data = $data;
        $this->charset = $charset;
    }

    function charset()
    {
        return $this->charset;
    }

    function data($charset=null)
    {
        if ((! is_null($charset)) && (strtolower($charset) != strtolower($this->charset))) {
            return iconv($this->charset, $charset.'//IGNORE', $this->data);
        }
        return $this->data;
    }
}

class RFC822Field
{
    protected $_name;
    protected $_body;

    function __construct($name, $body)
    {
        $this->_setName($name);
        $this->_setBody($body);
    }

    protected function _setName($value)
    {
        $this->_name = $value;
    }

    protected function _setBody($value)
    {
        if (is_string($value)) {
            $value = array($value);
        }
        $this->_body = $value;
    }

    function name()
    {
        if (func_num_args()) {
            if (func_num_args()==1) {
                $arg = func_get_arg(0);
                $this->_setName($arg);
            } else {
                throw new Exception();
            }
        } else {
            return $this->_name;
        }
    }

    function body()
    {
        if (func_num_args()) {
            if (func_num_args()==1) {
                $arg = func_get_arg(0);
                $this->_setBody($arg);
            } else {
                throw new Exception();
            }
        } else {
            return $this->_body;
        }
    }

    protected function toStringBody()
    {
        $result = "";
        foreach ($this->_body as $line) {
            if (strlen($result)) {
                $result .= "\r\n\t";
            }
            $result .= $line;
        }
        if (strlen($result)) {
            $result = " " . $result;
        }
        return $result;
    }

    function toString()
    {
        return $this->_name . ":" . $this->toStringBody() . "\r\n";
    }
}

class MIMEParam
{
    protected $_name;
    protected $_value;

    function __construct($name, $value)
    {
        $this->_setName($name);
        $this->_setValue($value);
    }

    protected function _setName($value)
    {
        $this->_name = $value;
    }

    protected function _setValue($value)
    {
        $this->_value = $value;
    }

    function name()
    {
        if (func_num_args()) {
            if (func_num_args()==1) {
                $arg = func_get_arg(0);
                $this->_setName($arg);
            } else {
                throw new Exception();
            }
        } else {
            return $this->_name;
        }
    }

    function value()
    {
        if (func_num_args()) {
            if (func_num_args()==1) {
                $arg = func_get_arg(0);
                $this->_setValue($arg);
            } else {
                throw new Exception();
            }
        } else {
            return $this->_value;
        }
    }

    function toString()
    {
        return $this->_name . "=" . $this->_value;
    }
}

class MIMEMessage
{
    protected $ContentTransferEncoding;
    protected $ContentType;
    protected $ContentTypeParams;
    protected $msg;
    protected $add_headers;
    protected $_content_id;

    const DEFAULT_ENCODING = '';
    const DEFAULT_CONTENNT_TYPE = 'text/plain';

    function __construct($msg, $charset = "")
    {
        if ($charset) {
            $msg = new CData($msg, $charset);
        } else {
            $msg = new CData($msg);
        }

        $this->msg = $msg;
        $this->ContentTransferEncoding = self::DEFAULT_ENCODING;
        $this->SetContentType(self::DEFAULT_CONTENNT_TYPE);
        $this->add_headers = array();
        $this->_content_id = "";
    }

    function SetContentType($value, $params = array())
    {
        $this->ContentType       = $value;
        $this->ContentTypeParams = $params;
    }

    function SetContentID($value)
    {
        $this->_content_id = $value;
    }

    function SetContentDescription($value)
    {
        for ($i=0; $i < count($this->add_headers); $i++) {
            if (strtolower($this->add_headers[$i]->name()) == 'content-description') {
                unset($this->add_headers[$i]);
                break;
            }
        }
        $this->AddHeader(RFC822Field('Content-Description', $value));
    }

    function AddHeader($value)
    {
        $this->add_headers[] = $value;
    }

    function SetContentTransferEncoding($value)
    {
        $this->ContentTransferEncoding = $value;
    }

    function toStringContent()
    {
        $charset = $this->msg->charset();
        foreach ($this->ContentTypeParams as $param) {
            if (strtolower($param->name()) == 'charset') {
                $charset = $param->value();
                break;
            }
        }
        $data = $this->msg->data($charset);

        switch (strtolower($this->ContentTransferEncoding)) {

        case 'base64':
            return chunk_split(base64_encode($data));
        case '8bit':
            return $data;
        case 'quoted-printable':
            return imap_8bit($data);
        default:
            return $data;
        }
    }

    function toStringHeaders()
    {
        $result = "";
        foreach ($this->add_headers as $header) {
            $result .= $header->toString();
        }

        if ($this->_content_id) {
            $result .= RFC822Field('Content-ID', "<{$this->_content_id}>")->toString();
        }

        if ($this->ContentTransferEncoding) {
            $result .= RFC822Field('Content-Transfer-Encoding', $this->ContentTransferEncoding)->toString();
        }

        ////////////
        $num_params = count($this->ContentTypeParams);
        $params = array($this->ContentType . ($num_params ? ";" : ""));
        for ($i = 0; $i < $num_params; $i++) {
            print_r($this->ContentTypeParams[$i]);
            $params[$i + 1] = $this->ContentTypeParams[$i]->toString() . ($num_params < $i + 1 ? ";" : "");
        }
        $result .= RFC822Field('Content-Type', $params)->toString();
        ////////////

        return $result;
    }

    function toString()
    {
        $result  = $this->toStringHeaders();
        $result .= "\r\n";
        $result .= $this->toStringContent();
        $result .= "\r\n";
        return $result;
    }
}

class MIMEMultipart extends MIMEMessage
{
    protected $parts;
    protected $boundary;
    protected $type;

    function __construct($type)
    {
        parent::__construct("");

        $this->SetMultipartType($type);
        $this->parts = array ();
        $this->SetBoundary('b_o_u_n_d_a_r_y_' . (time().rand(9999999, 1000000)));
    }

    function AddPart(MIMEMessage $msg)
    {
        $this->parts[] = $msg;
    }

    function AddAttachment(MIMEMessage $msg, $fname = null)
    {
        $params = array("attachment" . (!empty($fname) ? ";" : ""));
        if (!empty($fname)) {
            $params[] = MIMEParam("filename", $fname)->toString();
        }
        $msg->AddHeader(RFC822Field('Content-Disposition', $params));
        $this->AddPart($msg);
    }

    function AddInline(MIMEMessage $msg, $fname = null)
    {
        $params = array("inline" . (!empty($fname) ? ";" : ""));
        if (!empty($fname)) {
            $params[] = MIMEParam("filename", $fname)->toString();
        }
        $msg->AddHeader(RFC822Field('Content-Disposition', $params));
        $this->AddPart($msg);
    }

    function SetBoundary($boundary)
    {
        $this->boundary = $boundary;
    }

    function SetMultipartType($type, $params=array())
    {
        $this->type = $type;
        $this->ContentType = "multipart/{$this->type}";
        $this->ContentTypeParams[] = MIMEParam('boundary', $this->boundary);
        foreach ($params as $param) {
            $this->ContentTypeParams[] = $param;
        }
    }

    function toStringContent()
    {
        $result = "";
        foreach ($this->parts as $part) {
            $result .= "--{$this->boundary}\r\n";
            $result .= $part->toString();
        }
        $result .= "--{$this->boundary}--\r\n";

        return $result;
    }

}

class MIMEText extends MIMEMessage
{
    function __construct($msg, $charset = "")
    {
        parent::__construct($msg, $charset);

        $this->SetContentType('text/plain', array('charset' => $this->msg->charset()));
    }
}

class MIMEHTML extends MIMEMessage
{
    function __construct($msg, $charset = "")
    {
        parent::__construct($msg, $charset);

        $this->SetContentType('text/html', array('charset' => $this->msg->charset()));
    }
}

class MIMEAlternative extends MIMEMultipart
{
    function __construct()
    {
        parent::__construct('alternative');

        $args = func_get_args();
        foreach ($args as $msg) {
            $this->AddPart($msg);
        }
    }
}

class MIMEMixed extends MIMEMultipart
{
    function __construct()
    {
        parent::__construct('mixed');

        $args = func_get_args();
        foreach ($args as $msg) {
            $this->AddPart($msg);
        }
    }
}

class MIMERelated extends MIMEMultipart
{
    function __construct()
    {
        parent::__construct('related');

        $args = func_get_args();
        foreach ($args as $msg) {
            $this->AddInline($msg);
        }
    }

    function toStringHeaders()
    {
        if (count($this->parts)) {
            $first =& $this->parts[0];
            $this->ContentTypeParams[] = MIMEParam('type', $first->ContentType);
            if ($first->_content_id) {
                $this->ContentTypeParams[] = MIMEParam('start', '"<' . $first->_content_id . '>"');
            }
        }

        return parent::toStringHeaders();
    }

}

function CData()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function RFC822Field()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function MIMEParam()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function MIMEMessage()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function MIMEMultipart()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function MIMEAlternative()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function MIMEText()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function MIMEHTML()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function MIMEMixed()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

function MIMERelated()
{
    $args = func_get_args();
    return ____createO(__FUNCTION__, $args);
}

?>